﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using Itau.SC.EnterpriseLib.Data;

namespace EnterpriseLibraryWrapper
{
    public class DataAccessMockWrapper : IDataAccessWrapper
    {

        public IList<ParameterInWrapper> ParameterIn { get; set; }
        public IList<ParameterOutWrapper> ParameterOut { get; set; }
        public string Ambiente { get; set; }
        public DbTransaction Transaction { get; set; }

        public DataAccessMockWrapper()
        {
            this.ParameterIn = new List<ParameterInWrapper>();
            this.ParameterOut = new List<ParameterOutWrapper>();
        }

        public DataSet ExecuteDataSet(string storedProcedureName)
        {
            DatabaseMock db = new DatabaseMock();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);

            foreach(ParameterInWrapper parameterIn in ParameterIn)
            {
                db.AddInParameter(dbCommand, parameterIn.ParameterName, parameterIn.ParameterType, parameterIn.ParameterValue);
            }

            foreach (ParameterOutWrapper parameterOut in ParameterOut)
            {
                db.AddOutParameter(dbCommand, parameterOut.ParameterName, parameterOut.ParameterType, parameterOut.ParameterSize);
            }

            return db.ExecuteDataSet(dbCommand);
        }

        public int ExecuteNonQuery(string storedProcedureName)
        {
            DatabaseMock db = new DatabaseMock();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);

            foreach (ParameterInWrapper parameterIn in ParameterIn)
            {
                db.AddInParameter(dbCommand, parameterIn.ParameterName, parameterIn.ParameterType, parameterIn.ParameterValue);
            }

            foreach (ParameterOutWrapper parameterOut in ParameterOut)
            {
                db.AddOutParameter(dbCommand, parameterOut.ParameterName, parameterOut.ParameterType, parameterOut.ParameterSize);
            }

            int rowsAffected = db.ExecuteNonQuery(dbCommand);

            UpdateParametersOut(db);

            return rowsAffected;
        }

        private void UpdateParametersOut(DatabaseMock db)
        {
            IList<Itau.SC.EnterpriseLib.Data.ParameterOutWrapper> parametrosOut = db.GetOutParameters();

            foreach (Itau.SC.EnterpriseLib.Data.ParameterOutWrapper parametroOut in parametrosOut) 
            {
                ParameterOutWrapper parametro = this.ParameterOut.First(x => x.ParameterName.Equals(parametroOut.ParameterName));
                parametro.ParameterValue = parametroOut.ParameterValue;
            }
        }

        public object ExecuteScalar(string storedProcedureName)
        {
            DatabaseMock db = new DatabaseMock();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);

            foreach (ParameterInWrapper parameterIn in ParameterIn)
            {
                db.AddInParameter(dbCommand, parameterIn.ParameterName, parameterIn.ParameterType, parameterIn.ParameterValue);
            }

            foreach (ParameterOutWrapper parameterOut in ParameterOut)
            {
                db.AddOutParameter(dbCommand, parameterOut.ParameterName, parameterOut.ParameterType, parameterOut.ParameterSize);
            }

            return db.ExecuteScalar(dbCommand);
        }

        public IDataReader ExecuteReader(string storedProcedureName)
        {
            DatabaseMock db = new DatabaseMock();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);

            foreach (ParameterInWrapper parameterIn in ParameterIn)
            {
                db.AddInParameter(dbCommand, parameterIn.ParameterName, parameterIn.ParameterType, parameterIn.ParameterValue);
            }

            foreach (ParameterOutWrapper parameterOut in ParameterOut)
            {
                db.AddOutParameter(dbCommand, parameterOut.ParameterName, parameterOut.ParameterType, parameterOut.ParameterSize);
            }

            return db.ExecuteReader(dbCommand);
        }

        public DataSet ExecuteParameterToDataSet(string storedProcedureName)
        {
            DatabaseMock db = new DatabaseMock();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName);
            DataSet ds = new DataSet();
            DataTable dt = new DataTable();
            DataRow dr = dt.NewRow();

            foreach (ParameterInWrapper parameterIn in ParameterIn)
            {
                db.AddInParameter(dbCommand, parameterIn.ParameterName, parameterIn.ParameterType, parameterIn.ParameterValue);
                dt.Columns.Add(RemoverArrouba(parameterIn.ParameterName.ToString()), ConvertType(parameterIn.ParameterType));
                dr[RemoverArrouba(parameterIn.ParameterName)] = parameterIn.ParameterValue;
            }

            foreach (ParameterOutWrapper parameterOut in ParameterOut)
            {
                db.AddOutParameter(dbCommand, parameterOut.ParameterName, parameterOut.ParameterType, parameterOut.ParameterSize);
                dt.Columns.Add(RemoverArrouba(parameterOut.ParameterName.ToString()), ConvertType(parameterOut.ParameterType));
            }

            int retProc = db.ExecuteNonQuery(dbCommand);

            UpdateParametersOut(db);

            if (retProc > 0)
            {
                foreach (ParameterOutWrapper parameterOut in ParameterOut)
                {
                    dr[RemoverArrouba(parameterOut.ParameterName)] = parameterOut.ParameterValue;
                }
                dt.Rows.Add(dr);
            }

            ds.Tables.Add(dt);

            return ds;
        }

        private string RemoverArrouba(string nomeParametro)
        {
            return nomeParametro.Replace("@", string.Empty);
        }

        private Type ConvertType(DbType dbType)
        {
            Type toReturn = typeof(DBNull);

            switch (dbType)
            {
                case DbType.String:
                    toReturn = typeof(string);
                    break;

                case DbType.UInt64:
                    toReturn = typeof(UInt64);
                    break;

                case DbType.Int64:
                    toReturn = typeof(Int64);
                    break;

                case DbType.Int32:
                    toReturn = typeof(Int32);
                    break;

                case DbType.UInt32:
                    toReturn = typeof(UInt32);
                    break;

                case DbType.Single:
                    toReturn = typeof(float);
                    break;

                case DbType.Date:
                    toReturn = typeof(DateTime);
                    break;

                case DbType.DateTime:
                    toReturn = typeof(DateTime);
                    break;

                case DbType.Time:
                    toReturn = typeof(DateTime);
                    break;

                case DbType.StringFixedLength:
                    toReturn = typeof(string);
                    break;

                case DbType.UInt16:
                    toReturn = typeof(UInt16);
                    break;

                case DbType.Int16:
                    toReturn = typeof(Int16);
                    break;

                case DbType.SByte:
                    toReturn = typeof(byte);
                    break;

                case DbType.Object:
                    toReturn = typeof(object);
                    break;

                case DbType.AnsiString:
                    toReturn = typeof(string);
                    break;

                case DbType.AnsiStringFixedLength:
                    toReturn = typeof(string);
                    break;

                case DbType.VarNumeric:
                    toReturn = typeof(decimal);
                    break;

                case DbType.Currency:
                    toReturn = typeof(double);
                    break;

                case DbType.Binary:
                    toReturn = typeof(byte[]);
                    break;

                case DbType.Decimal:
                    toReturn = typeof(decimal);
                    break;

                case DbType.Double:
                    toReturn = typeof(Double);
                    break;

                case DbType.Guid:
                    toReturn = typeof(Guid);
                    break;

                case DbType.Boolean:
                    toReturn = typeof(bool);
                    break;
            }

            return toReturn;
        }

        #region IDataAccessWrapper Members


        public void BeginTransaction()
        {
        }

        public void CommitTransaction()
        {
        }

        public void RollBackTransaction()
        {
        }

        public void CloseConnection()
        {
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
